#include "Z80.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::Add( u8 Data ) {
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( (u16)((m_AF.H & 0x0F) + (Data & 0x0F)) > 0x000F ) m_AF.L |= FLAG_H;
    if( (u16)( m_AF.H + Data ) > 0x00FF ) m_AF.L |= FLAG_C;
    m_AF.H += Data;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::AddWithCarry( u8 Data ) {
    if( TestFlag(m_AF.L, FLAG_C) ) Data += 1;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( (u16)((m_AF.H & 0x0F) + (Data & 0x0F)) > 0x000F ) m_AF.L |= FLAG_H;
    if( (u16)( m_AF.H + Data ) > 0x00FF ) m_AF.L |= FLAG_C;
    m_AF.H += Data;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::AND( u8 Data ) {
    m_AF.H &= Data;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_C );
    m_AF.L |= FLAG_H;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::Call( u16 Address ) {
    PushWord( m_PC.W );
    m_PC.W = Address;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::Compare_8Bit( u8 Reg, u8 Data ) {
    m_AF.L &= ~( FLAG_Z | FLAG_H | FLAG_C );
    if( Reg - Data == 0 ) m_AF.L |= FLAG_Z;
    m_AF.L |= FLAG_N;
    if( (Reg & 0x0F) < (Data & 0x0F) ) m_AF.L |= FLAG_H;
    if( Reg < Data ) m_AF.L |= FLAG_C;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::Decrement_8Bit( u8 &Reg ) {
    m_AF.L &= ~( FLAG_Z | FLAG_H );
    m_AF.L |= FLAG_N;
    if( (Reg & 0x0F) == 0 ) m_AF.L |= FLAG_H;
    Reg--;
    if( Reg == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::Increment_8Bit( u8 &Reg ) {
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H );
    if( (Reg & 0x0F) == 0x0F ) m_AF.L |= FLAG_H;
    Reg++;
    if( Reg == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::LDHL_SPn() {
    s8 Data = (s8)m_Read( m_PC.W++ );
    u32 Value = m_SP.W + Data;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( (u32)(m_HL.W + Value) > 0xFFFF ) m_AF.L |= FLAG_C;
    if( (u16)((m_SP.W & 0x000F) + (Data & 0x0F)) > 0x0F ) m_AF.L |= FLAG_H;
    m_HL.W += ( Value & 0xFFFF );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::OR( u8 Data ) {
    m_AF.H |= Data;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::RotateLeft() {
    u8 old_acc = m_AF.H;
    m_AF.H <<= 1;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( TestBit(old_acc, 7) ) {
        m_AF.H |= 1;
        m_AF.L |= FLAG_C;
    }
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::RotateLeftWithCarry() {
    u8 old_acc = m_AF.H;
    bool old_carry = TestFlag(m_AF.L, FLAG_C);
    m_AF.H <<= 1;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( TestBit(old_acc, 7) ) m_AF.L |= FLAG_C;
    if( old_carry ) m_AF.H |= 0x01;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::RotateRight() {
    u8 old_acc = m_AF.H;
    m_AF.H >>= 1;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( TestBit(old_acc, 0) ) {
        m_AF.H |= 0x80;
        m_AF.L |= FLAG_C;
    }
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::RotateRightWithCarry() {
    u8 old_acc = m_AF.H;
    bool old_carry = TestFlag(m_AF.L, FLAG_C);
    m_AF.H >>= 1;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( TestBit(old_acc, 0) ) m_AF.L |= FLAG_C;
    if( old_carry ) m_AF.H |= 0x80;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::DecimalAdjust() {
    // robado de "http://gbx-emu.googlecode.com/svn-history/r64/trunk/cpu.cpp". no se que carajo hace en realidad...
    u8 tmp = 0;
    u8 lower_nibble = m_AF.H & 0x0F;
    u8 higher_nibble = (m_AF.H & 0xF0) >> 4;
    
    m_AF.L &= ~( FLAG_Z );

    // la ultima instruccion fue una suma
    if( !TestFlag(m_AF.L, FLAG_N) ) {
        if( TestFlag(m_AF.L, FLAG_H) || (lower_nibble > 0x09) ) tmp += 0x06;
        if( TestFlag(m_AF.L, FLAG_C) || (higher_nibble > 0x09) || ((higher_nibble == 9) && (lower_nibble > 9)) ) tmp += 0x60;
        if( tmp > 0x5F) m_AF.L |= FLAG_C;
        else m_AF.L &= ~( FLAG_C );
        
    // la ultima instruccion fue una resta
    } else {
        if( !TestFlag(m_AF.L, FLAG_C) && TestFlag(m_AF.L, FLAG_H) ) {
            tmp += 0xFA;
            m_AF.L &= ~( FLAG_C );
        } else if( TestFlag(m_AF.L, FLAG_C) && !TestFlag(m_AF.L, FLAG_H) ) {
            tmp += 0xA0;
            m_AF.L |= FLAG_C;
        } else if( TestFlag(m_AF.L, FLAG_C) && TestFlag(m_AF.L, FLAG_H) ) {
            tmp += 0x9A;
            m_AF.L |= FLAG_C;
        } else m_AF.L &= ~( FLAG_C );
    }
    
    if( tmp == 0 ) m_AF.L |= FLAG_Z;
    m_AF.L &= ~( FLAG_H );
    m_AF.H -= tmp;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::SubtractWithCarry( u8 Data ) {
    if( TestFlag(m_AF.L, FLAG_C) ) Data += 1;
    m_AF.L &= ~( FLAG_Z | FLAG_H | FLAG_C );
    if( (m_AF.H & 0x0F) < (Data & 0x0F) ) m_AF.L |= FLAG_H;
    if( m_AF.H < Data ) m_AF.L |= FLAG_C;
    m_AF.H -= Data;
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
    m_AF.L |= FLAG_N;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::BIT( u8 Data, int Bit ) {
    m_AF.L &= ~( FLAG_Z | FLAG_N );
    m_AF.L |= FLAG_H;
    if( !TestBit(Data, Bit) ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Z80::XOR( u8 Data ) {
    m_AF.H ^= Data;
    m_AF.L &= ~( FLAG_Z | FLAG_N | FLAG_H | FLAG_C );
    if( m_AF.H == 0 ) m_AF.L |= FLAG_Z;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////